package com.server.service;

import com.server.dal.DatabaseHelper;

import java.io.*;
import java.net.Socket;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author e4glet
 * 2025年3月5日
 * */

// 客户端处理模块
public class ClientHandler implements Runnable {
    private Socket clientSocket;
    private ConcurrentHashMap<Integer, Socket> onlineUsers;

    // 构造函数
    public ClientHandler(Socket socket,ConcurrentHashMap<Integer, Socket> onlineUsers) {
        this.clientSocket = socket;
        this.onlineUsers = onlineUsers;
    }

    // 重写run方法
    // 服务器端处理客户端请求
    @Override
    public void run() {
        try {
            InputStream input = clientSocket.getInputStream();
            OutputStream output = clientSocket.getOutputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            PrintWriter writer = new PrintWriter(output, true);

            String request;
            // 使用switch语句来处理客户端请求，根据不同的命令调用不同的处理方法
            while ((request = reader.readLine()) != null) {
                System.out.println("收到客户端请求: " + request);
                String[] parts = request.split(" ");
                // 提取指令选择处理函数
                String command = parts[0];
                switch (command) {
                    case "REGISTER":
                        handleRegister(parts, writer);
                        break;
                    case "LOGIN":
                        handleLogin(parts, writer);
                        break;
                    case "SEARCH_USER":
                        handleSearchUser(parts, writer);
                        break;
                    case "ADD_FRIEND":
                        handleAddFriend(parts, writer);
                        break;
                    case "SEND_MESSAGE":
                        handleSendMessage(parts, writer);
                        break;
                    case "CHECK_MESSAGES":
                        handleCheckMessages(parts, writer);
                        break;
                    case "GET_FRIENDS":
                        handleGetFriends(parts, writer);
                        break;
                    case "GET_MESSAGES":
                        handleGetMessages(parts, writer);
                        break;
                    case "LOGOUT":
                        handleLogout(parts, writer);
                        return; // 在登出时跳出循环
                    default:
                        break;
                }
            }

        } catch (IOException | SQLException e) {
            if (e.getMessage().contains("Connection reset")) {
                System.out.println("客户端异常断开，移除在线状态");
                onlineUsers.values().removeIf(socket -> socket.isClosed());
            }
        } finally {
            try {
                clientSocket.close();
                System.out.println("客户端连接已关闭");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 重构优化代码结构
     * */

    // 服务器端用户注册处理函数
    private void handleRegister(String[] parts, PrintWriter writer) throws SQLException {
        String email = parts[1];
        String nickname = parts[2];
        String password = parts[3];
        boolean success = DatabaseHelper.registerUser(email, nickname, password);
        System.out.println("用户注册: " + email + (success ? " 成功" : " 失败"));
        writer.println(success ? "REGISTER_SUCCESS" : "REGISTER_FAIL");
    }

    /**
     * 服务器端用户登录处理函数
     * */ 
    private void handleLogin(String[] parts, PrintWriter writer) throws SQLException {
        String account = parts[1];
        String password = parts[2];
        boolean success = DatabaseHelper.loginUser(account, password);
        if (success) {
            int userId = DatabaseHelper.getUserId(account);
            if (userId != -1) {
                // 修改在线socket用户集合，添加登录上线用户socket
                onlineUsers.put(userId,this.clientSocket);
                // 修改数据库中用户在线状态
                DatabaseHelper.updateUserOnlineStatus(userId, true);
                System.out.println("用户登录成功 - ID: " + userId + ", 账号: " + account);
                writer.println("LOGIN_SUCCESS");
                writer.println(userId);
                // 通知好友更新好友列表
                handleUpdateFriendListByUserId(userId);
            } else {
                System.out.println("用户ID获取失败 - 账号: " + account);
                writer.println("LOGIN_FAIL");
            }
        } else {
            System.out.println("用户登录失败 - 账号: " + account);
            writer.println("LOGIN_FAIL");
        }
    }

    /**
     * 服务器端添加好友搜索处理方法
     * 添加好友时先搜索好友
     * */
    private void handleSearchUser(String[] parts, PrintWriter writer) throws SQLException {
        String account = parts[1];
        System.out.println("搜索用户: " + account);
        Map<String, Object> userInfo = DatabaseHelper.searchUserByAccount(account);
        if (userInfo != null) {
            int foundId = (int) userInfo.get("id");
            String nickname = (String) userInfo.get("nickname");
            System.out.println("找到用户 - ID: " + foundId + ", 昵称: " + nickname);
            writer.println("SEARCH_USER_SUCCESS " + foundId + " " + nickname);
        } else {
            System.out.println("未找到用户: " + account);
            writer.println("SEARCH_USER_FAIL");
        }
    }

    /**
     * 服务器端添加好友处理函数
     * 根据客户端请求类型添加好友
     * */
    private void handleAddFriend(String[] parts, PrintWriter writer) throws SQLException {
        int userId = Integer.parseInt(parts[1]);
        int friendId = Integer.parseInt(parts[2]);
        System.out.println("好友添加请求 - 用户ID: " + userId + ", 好友ID: " + friendId);
        if (DatabaseHelper.checkFriendExists(userId, friendId)) {
            System.out.println("好友关系已存在");
            writer.println("FRIEND_ALREADY_EXISTS");
        } else {
            boolean success = DatabaseHelper.addFriend(userId, friendId);
            System.out.println("添加好友" + (success ? "成功" : "失败"));
            writer.println(success ? "ADD_FRIEND_SUCCESS" : "ADD_FRIEND_FAIL");
        }
    }

    // 处理和扩展该方法
    /**
     * 服务器端发送消息处理函数
     * 从发送方收到消息，再通过服务器中转发给接收方
     */
    private void handleSendMessage(String[] parts, PrintWriter writer) throws SQLException {
        int senderId = Integer.parseInt(parts[1]); //发送者id
        int receiverId = Integer.parseInt(parts[2]); //接收者id
        String message = parts[3]; //消息内容

        // 保存消息到服务器数据库
        DatabaseHelper.saveMessage(senderId, receiverId, message);
        
        // 构建私聊信息结构
        // MESSAGE_SENT_PRIVATE {接收者id},{发送者id},{接收的消息内容}
        String responseMessage = "MESSAGE_RECEIVER_PRIVATE " + receiverId + "," + senderId + "," + message;
        
        // 找到接收者的Socket并发送消息
        Socket receiverSocket = onlineUsers.get(receiverId);
        if (receiverSocket != null) {
            try {
                PrintWriter receiverWriter = new PrintWriter(receiverSocket.getOutputStream(), true);
                receiverWriter.println(responseMessage);
                System.out.println("服务器端转发消息给用户: " + receiverId);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("接收者id"+receiverId+"不在线，消息保存到数据库");
        }
        
        System.out.println("服务器端转发消息给另一个用户: " + responseMessage.toString());
    }


    private void handleCheckMessages(String[] parts, PrintWriter writer) throws SQLException {
        int userId = Integer.parseInt(parts[1]);
        writer.println("NO_MESSAGE");
    }

    /**
     * 服务器端获取用户在线好友列表，并发送给指定客户端
     * 发送的内容包括消息类型FRIEND_LIST，用户id，好友昵称及在线状态
     * */
    private void handleGetFriends(String[] parts, PrintWriter writer) throws SQLException {
        int userId = Integer.parseInt(parts[1]);
        List<Map<String, Object>> friends = DatabaseHelper.getFriendList(userId);
        StringBuilder response = new StringBuilder("FRIEND_LIST ");
        for (Map<String, Object> friend : friends) {
            response.append(friend.get("id")).append(",")
                    .append(friend.get("nickname")).append(",")
                    .append((Boolean) friend.get("online") ? "1" : "0").append(";");
        }
        writer.println(response.toString());
        System.out.println("发送好友状态列表: " + response.toString());
    }

    /**
     * 服务器端用户注销处理函数
     * 收到客户端用户注销消息时，服务器更新用户在线状态
     * */
    private void handleLogout(String[] parts, PrintWriter writer) throws SQLException {
        int userId = Integer.parseInt(parts[1]);
        // 从在线socket用户集合中移除下线用户
        onlineUsers.values().remove(this.clientSocket);
        // 更新数据库中用户在线状态
        DatabaseHelper.updateUserOnlineStatus(userId, false);
        System.out.println("用户登出 - ID: " + userId);
        writer.println("LOGOUT_SUCCESS");
        // 通知好友更新在线好友列表
        handleUpdateFriendListByUserId(userId);
    }

    /**
     * 用户登录或注销后，通知其好友更新在线列表
     * */
    private void handleUpdateFriendListByUserId(Integer userId) throws SQLException{
        //获取当前用户的好友列表
        List<Integer> friendList = DatabaseHelper.getUserListByUserId(userId);

        for(Integer friendId : friendList){
            Socket friendSocket = onlineUsers.get(friendId);
            if (friendSocket != null && !friendSocket.isClosed()){
                // 向在线好友发送更新好友列表通知
                try{
                    // 通过Socket获取输出流，发送通知
                    PrintWriter friendWriter = new PrintWriter(friendSocket.getOutputStream(), true);
                    friendWriter.println("UPDATE_FRIEND_LIST_STATUS");
                    System.out.println("调试日志：发送给好友"+friendId+"更新好友列表");
                }catch (Exception e){
                    // 若连接失效，从在线列表中移除
                    onlineUsers.remove(friendId);
                    System.out.println("好友 " + friendId + " 的连接已失效，移除在线状态");
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 获取历史消息
     * */
    // 新增处理方法
    private void handleGetMessages(String[] parts, PrintWriter writer) throws SQLException {
        int userId = Integer.parseInt(parts[1]);
        int friendId = Integer.parseInt(parts[2]);
//        List<String> messages = DatabaseHelper.getMessages(userId, friendId);
        StringBuilder response = new StringBuilder("MESSAGES_HISTORY ");
//        for (String msg : messages) {
//            response.append(msg).append(";");
//        }
        writer.println(response.toString());
    }
}
